package com.whale.api;

import com.alibaba.fastjson.JSON;
import org.apache.flink.api.common.serialization.SimpleStringEncoder;
import org.apache.flink.api.common.typeinfo.TypeHint;
import org.apache.flink.api.java.tuple.Tuple5;
import org.apache.flink.connector.file.sink.FileSink;
import org.apache.flink.core.fs.Path;
import org.apache.flink.streaming.api.CheckpointingMode;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.sink.filesystem.OutputFileConfig;
import org.apache.flink.streaming.api.functions.sink.filesystem.bucketassigners.DateTimeBucketAssigner;
import org.apache.flink.streaming.api.functions.sink.filesystem.rollingpolicies.DefaultRollingPolicy;

import java.util.Map;

/**
 * 行格式FileSink.forRowFormat
 *
 * StreamFileSink 默认会在一个目录下操作，比如我们这个例子的【d:/filesink/】
 * 默认会按照小时进行生成文件目录
 * 然后在按照并行度，同时开启多个线程同时操作，期间还会根据【滚动策略】划分多个文件
 */
public class _08_FIleSInk_Row {
    public static void main(String[] args) throws Exception {

        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        env.enableCheckpointing(2000, CheckpointingMode.EXACTLY_ONCE);
        env.getCheckpointConfig().setCheckpointStorage("file:///d:/ckpt");

        env.setParallelism(2);

        DataStreamSource<EventLog> streamSource = env.addSource(new MySourceFunction());

        // 输出到文件
        streamSource.map(bean -> Tuple5.of(bean.getEventId(), bean.getGuid(), bean.getEventInfo(), bean.getSessionId(), bean.getTimeStamp())).returns(new TypeHint<Tuple5<String, Long, Map<String, String>, String, Long>>() {
        });


        /**
         * 应用  StreamFileSink 算子，来将数据输出到  文件系统
         */

        /**
         * 1. 输出为 行格式
         */
        // 构造一个FileSink对象
        FileSink<String> rowSink = FileSink
                .forRowFormat(new Path("d:/filesink/"), new SimpleStringEncoder<String>("utf-8"))
                // 文件的滚动策略 （间隔时长10s，或文件大小达到 5M，就进行文件切换
                .withRollingPolicy(
                        DefaultRollingPolicy.builder()
                                .withRolloverInterval(10 * 1000) // 类似log日志，滚动策略，10s后生成新文件
                                .withMaxPartSize(5 * 1024 * 1024).build()) // 文件大小到5MB的时候生成新文件
                // 分桶的策略（划分子文件夹的策略）
                .withBucketAssigner(new DateTimeBucketAssigner<String>())
                .withBucketCheckInterval(5)
                // 输出文件的文件名相关配置
                .withOutputFileConfig(OutputFileConfig.builder().withPartPrefix("doitedu").withPartSuffix(".txt").build())
                .build();

        // 然后添加到流，进行输出
        streamSource.map(JSON::toJSONString)
                //.addSink()  /* SinkFunction实现类对象,用addSink() 来添加*/
                .sinkTo(rowSink); /*Sink 的实现类对象,用 sinkTo()来添加  */

        env.execute();
    }
}
